package com.intelligentpension.kotlinbluetooth.ble

import android.Manifest
import android.annotation.SuppressLint
import android.bluetooth.*
import android.bluetooth.le.ScanCallback
import android.bluetooth.le.ScanResult
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.View
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.hjq.toast.ToastUtils
import com.intelligentpension.kotlinbluetooth.R
import com.intelligentpension.kotlinbluetooth.adapter.BLEDevAdapter
import com.intelligentpension.kotlinbluetooth.been.BleDev
import com.intelligentpension.kotlinbluetooth.utils.Contect


import com.intelligentpension.kotlinbluetooth.utils.ThreadUtils
import com.orhanobut.logger.Logger
import java.util.*
import kotlin.collections.ArrayList

/**
 * 版权：点赞 版权所有
 * author :赵航
 * @e-mail: zhaohangcn@gmail.com
 * time：2022/3/28
 * describe ：客户端的核心类是BluetoothGatt
 * 数据的核心类是BluetoothGattCharacteristic
 */

class LowPowerCustomerActivity : AppCompatActivity(), View.OnClickListener {
    private lateinit var mRediscover: Button
    private lateinit var mRecycler: RecyclerView
    private lateinit var mAdapter: BLEDevAdapter
    private lateinit var mRead: Button
    private lateinit var mSetting: Button
    private lateinit var mWrite: Button
    private lateinit var mSendMessage: EditText
    private lateinit var mTvTip: TextView
    private var mBluetoothGatt: BluetoothGatt? = null
    private var mList: MutableList<BleDev> = ArrayList()

    private var isConnect: Boolean = false
    private var isScanning: Boolean = false
    private var mHandler = Handler(Looper.myLooper()!!)
    private var mListBluetoothDevice: MutableList<BluetoothDevice> = ArrayList()

    //低功耗蓝牙的回调
    private var callback = object : BluetoothGattCallback() {
        /**
         * 监听当前的蓝牙连接状态,连接成功的回调
         */
        @SuppressLint("MissingPermission")
        override fun onConnectionStateChange(gatt: BluetoothGatt?, status: Int, newState: Int) {
            super.onConnectionStateChange(gatt, status, newState)
            var dev: BluetoothDevice? = gatt?.device
            Logger.e(String.format("onConnectionStateChange:%s,%s,%s,%s", dev?.name, dev?.address, status, newState))
            if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_CONNECTED) {
                isConnect = true
                gatt?.discoverServices() //启动服务发现,这样才能调用(onServicesDiscovered方法)
            } else {
                isConnect = false
                closeConn()
            }
            logTv(String.format(if (0 === status) if (2 === newState) "与[%s]连接成功" else "与[%s]连接断开" else "与[%s]连接出错,错误码:$status", dev))
        }

        @SuppressLint("MissingPermission")
        override fun onServicesDiscovered(gatt: BluetoothGatt?, status: Int) {
            super.onServicesDiscovered(gatt, status)
            Logger.e(String.format("onServicesDiscovered:%s,%s,%s", gatt?.device?.name, gatt?.device?.address, status))
            //BLE服务发现成功
            if (status == BluetoothGatt.GATT_SUCCESS) {

                // 遍历获取BLE服务Services/Characteristics/Descriptors的全部UUID
                var services = gatt?.services
                if (services != null) {

                    for (service in services) {

                        var allUUIDs = StringBuilder("UUIDs={\nS=" + service.uuid.toString())
                        var characteristics = service.characteristics

                        for (characteristic:BluetoothGattCharacteristic in characteristics) {
                            allUUIDs.append(",\nC=").append(characteristic.uuid)
                            var descriptors = characteristic.descriptors


                            //只接收发送过来的信息
                            if (characteristic.uuid.toString().equals(Contect.UUID_CHAR_WRITE)){
                                println("我找到我需要的特征")
                                //这个是个令牌,告诉硬件,用着UUID的特征来通讯
                                mBluetoothGatt?.setCharacteristicNotification(characteristic,true)
                            }


                            for (descriptor in descriptors) {
                                allUUIDs.append(",\nD=").append(descriptor.uuid)
                            }

                        }
                        allUUIDs.append("}")
                        Logger.e("onServicesDiscovered:$allUUIDs")
                        Logger.e("发现服务:$allUUIDs")
                    }
                }
            }
        }

        //读取数据的回调
        @SuppressLint("MissingPermission")
        override fun onCharacteristicRead(gatt: BluetoothGatt?, characteristic: BluetoothGattCharacteristic?, status: Int) {
            super.onCharacteristicRead(gatt, characteristic, status)
            var uuid = characteristic?.uuid
            var value = characteristic?.value
            var valueStr = ""
            if (value != null) {
                valueStr = String(value)
            }
            Logger.e(String.format("onCharacteristicRead:%s,%s,%s,%s,%s", gatt?.device?.name, gatt?.device?.address, uuid, valueStr, status))
            logTv("读取Characteristic[$uuid]:\n$valueStr")
        }

        //写入成功回调
        @SuppressLint("MissingPermission")
        override fun onCharacteristicWrite(gatt: BluetoothGatt?, characteristic: BluetoothGattCharacteristic?, status: Int) {
            super.onCharacteristicWrite(gatt, characteristic, status)
            var uuid = characteristic?.uuid
            var valueStr = ""
            if (characteristic != null) {
                valueStr = String(characteristic?.value)
            }
            Logger.e(String.format("onCharacteristicWrite:%s,%s,%s,%s,%s", gatt?.device?.name, gatt?.device?.address, uuid, valueStr, status))
            logTv("写入Characteristic[$uuid]:\n$valueStr")
        }

        //开启通知,如果Characteristic变化
        @SuppressLint("MissingPermission")
        override fun onCharacteristicChanged(gatt: BluetoothGatt?, characteristic: BluetoothGattCharacteristic?) {
            super.onCharacteristicChanged(gatt, characteristic)
            var uuid = characteristic?.uuid
            var valueStr = "";
            if (characteristic != null) valueStr = String(characteristic.value)
            Logger.e(String.format("onCharacteristicChanged:%s,%s,%s,%s", gatt?.device?.name, gatt?.device?.address, uuid, valueStr))
            logTv("通知Characteristic[$uuid]:\n$valueStr")
        }

        @SuppressLint("MissingPermission")
        override fun onDescriptorRead(gatt: BluetoothGatt?, descriptor: BluetoothGattDescriptor?, status: Int) {
            super.onDescriptorRead(gatt, descriptor, status)
            var uuid = descriptor?.uuid
            var valueStr = "";
            if (descriptor != null) valueStr = String(descriptor.value)
            Logger.e(String.format("onDescriptorRead:%s,%s,%s,%s", gatt?.device?.name, gatt?.device?.address, uuid, valueStr))
            logTv("读取Descriptor[$uuid]:\n$valueStr")
        }

        @SuppressLint("MissingPermission")
        override fun onDescriptorWrite(gatt: BluetoothGatt?, descriptor: BluetoothGattDescriptor?, status: Int) {
            super.onDescriptorWrite(gatt, descriptor, status)
            var uuid = descriptor?.uuid
            var valueStr = "";
            if (descriptor != null) {
                valueStr = Arrays.toString(descriptor.value)
            }
            Logger.e(String.format("onDescriptorWrite:%s,%s,%s,%s,%s", gatt?.device?.name, gatt?.device?.address, uuid, valueStr, status))
            logTv("写入Descriptor[$uuid]:\n$valueStr")
        }
    }

    //低功耗蓝牙扫描的结果
    private var mScanCallback = object : ScanCallback() {
        override fun onScanResult(callbackType: Int, result: ScanResult?) {
            super.onScanResult(callbackType, result)
            var device = result?.device
            if (device!=null&&!mListBluetoothDevice.contains(device)){
                mListBluetoothDevice.add(device)
                var dev = BleDev(result?.device,result)
                mList.add(dev)
            }
            mAdapter.notifyDataSetChanged()
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_low_power_customer)

        mRediscover = findViewById<Button>(R.id.rediscover)
        mRediscover.setOnClickListener(this@LowPowerCustomerActivity)

        mRecycler = findViewById<RecyclerView>(R.id.recycler)
        var layoutManager = LinearLayoutManager(this@LowPowerCustomerActivity)
        mRecycler.layoutManager = layoutManager
        mAdapter = BLEDevAdapter(R.layout.item_dev, mList)
        mRecycler.adapter = mAdapter
        mAdapter.setOnItemClickListener { _, _, position ->
            var dev = mList[position].dev
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
                    return@setOnItemClickListener
                }
            }
            closeConn()
            //连接蓝牙设备
            mBluetoothGatt = dev?.connectGatt(this@LowPowerCustomerActivity, false, callback)
            logTv(String.format("与[%s]开始连接............\n", dev))
        }
        //添加连接数据
        scanBle()

        mRead = findViewById<Button>(R.id.read)
        mRead.setOnClickListener(this@LowPowerCustomerActivity)
        mSetting = findViewById<Button>(R.id.setting)
        mSetting.setOnClickListener(this@LowPowerCustomerActivity)
        mWrite = findViewById<Button>(R.id.write)
        mWrite.setOnClickListener(this@LowPowerCustomerActivity)

        mSendMessage = findViewById<EditText>(R.id.send_message)
        mTvTip = findViewById<TextView>(R.id.tv_tip)

    }

    //扫描BLE蓝牙(不会扫描经典蓝牙)
    private fun scanBle() {
        mList.clear()
        isScanning = true
        val mBt: BluetoothAdapter =
            (getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager).adapter
        var bluetoothLeScanner = mBt.bluetoothLeScanner
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
                return
            }
        }
        //注意: BLE设备地址是动态变化(每隔一段时间都会变化),而经典蓝牙设备是出厂就固定不变了！
        //Android 5.0新增的扫描API,扫描返回的结果更友好,比如BLE广播数据以前是byte[] scanRecord,而新API帮我们解析成ScanRecord类
        //旧API是BluetoothAdapter.startLeScan(...)
        bluetoothLeScanner.startScan(mScanCallback)//开始扫描
        mHandler.postDelayed({
            bluetoothLeScanner.stopScan(mScanCallback)//停止扫描
            isScanning = false
        }, 3000)
    }

    override fun onClick(p0: View?) {
        when (p0?.id) {
            R.id.rediscover -> {
                if (isScanning){
                    ToastUtils.show("正在扫描....")
                }else{
                    scanBle()
                }
            }
            R.id.read -> {
                read()
            }
            R.id.setting -> {
                notice()
            }
            R.id.write -> {
                write()
            }
        }
    }

    // 设置通知Characteristic变化会回调->onCharacteristicChanged()
    @SuppressLint("MissingPermission")
    private fun notice() {
        var gattService = getGattService(Contect.UUID_SERVICE)
        if (gattService!=null){
            //通过UUID获取可通知的Characteristic
            var characteristic = gattService.getCharacteristic(Contect.UUID_CHAR_READ_NOTIFY)
            //设置Characteristic通知
            mBluetoothGatt?.setCharacteristicNotification(characteristic,true);

            //向Characteristic的Descriptor属性写入通知开关,使蓝牙设备主动向手机发送数据
            var descriptor = characteristic.getDescriptor(Contect.UUID_DESC_NOTITY)
            //和通知类似,单服务端不主动发数据,只指示客户读取数据
            descriptor.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
            mBluetoothGatt?.writeDescriptor(descriptor)
        }
    }
    //TODO:1,每次读写数据最多20个字节,如果超过,只能分包
    // 2,连续读写数据很容易失败,读写操作的间隔最好200ms以上,或等待上次回调完成后再进行下一次读写操作


    // 注意：连续频繁读写数据容易失败，读写操作间隔最好200ms以上，或等待上次回调完成后再进行下次读写操作！
    // 写入数据成功会回调->onCharacteristicWrite()
    @SuppressLint("MissingPermission")
    private fun write() {
        var gattService = getGattService(Contect.UUID_SERVICE)
        if (gattService!=null){
            var msg = mSendMessage.text.toString()
            var characteristic = gattService.getCharacteristic(Contect.UUID_CHAR_WRITE)
            characteristic.value = msg.toByteArray()//单次最多20个字节
            mBluetoothGatt?.writeCharacteristic(characteristic)
        }

    }

    // 注意：连续频繁读写数据容易失败，读写操作间隔最好200ms以上，或等待上次回调完成后再进行下次读写操作！
    // 读取数据成功会回调->onCharacteristicRead()
    @SuppressLint("MissingPermission")
    fun read(){
        var gattService = getGattService(Contect.UUID_SERVICE)
        if (gattService!=null){
            var characteristic = gattService.getCharacteristic(Contect.UUID_CHAR_READ_NOTIFY)
            mBluetoothGatt?.readCharacteristic(characteristic)
        }
    }

    //通过UUID获取服务
    private fun getGattService(uuid: UUID):BluetoothGattService? {
        if (!isConnect){
            ToastUtils.show("没有连接")
            return null
        }
        var service = mBluetoothGatt?.getService(uuid)
        if (service==null)
            ToastUtils.show("没有找到服务UUID=$uuid")
        return service

    }

    //BLE中心设备连接外围设备的数量有限(大概2~7个),在建立新连接之前必须释放旧连接资源,否则容易出现连接错误133
    @SuppressLint("MissingPermission")
    private fun closeConn() {
        mBluetoothGatt?.disconnect()
        mBluetoothGatt?.close()
    }

    fun logTv(msg: String) {
        if (isDestroyed) return
        ThreadUtils.executeMainThread {
            mTvTip.append(msg)
            ToastUtils.show(msg)
        }
    }
}